﻿#pragma once

#include <string>
#include <fstream>
#include <mutex>

class logs
{
public:
	enum type {
		// for level
		none = 0, fatal, error, warn, info, debug,
		// for cycle
		// yearly = 0, monthly, weekly, daily, hourly, minutely
	};

public:
	// 日志的输出等级, 高于此等级的日志不再输出, 默认info
	type level;

	// type cycle;
	// 日志是否输出全部信息, 默认每行最多只输出256字节
	bool detail;

	// 日志文件的最大字节数, 超出将自动写入到新文件, 默认100M
	std::streamoff limit;

protected:
	std::ostream *m_stream;
	std::streamoff m_size; // how many size write to file.
	std::string m_name; // log file name.
	std::ofstream m_fstream; // log file stream.
	std::mutex m_mutex;

public:
	logs();
	virtual ~logs();

	// 绑定日志到文件, 减号(-)表示标准输出, 默认输出到标准输出
	bool tie(const char *file);

	// 输出日志
	int logf(type lv, const char *fn, int ln, const char *fmt, ...) noexcept;

	// 以16进制格式输出内存
	static void hexdump(std::ostream &stm, const char *str, size_t len);

	// 以16进制格式输出内存
	inline void hexdump(const char *str, size_t len)
	{
		hexdump(*m_stream, str, len);
	}

	// 静态对象, 提供给plogf使用
	static logs glog;

protected:
	// 重新绑定文件
	bool retie();

private:
	logs(const logs&) = delete;
	logs(logs&&) = delete;
	logs &operator=(const logs&) = delete;
	logs &operator=(logs&&) = delete;
};

// 输出日志, 使用静态对象logs::glog
// type 日志等级
// format 输出格式
// 示例: logf(log::warn, "error code: %d, %s", 99, "Unknown error.");
// 输出: 2001-01-01 01:01:01 [ WARN] [main] error code: 99, Unknown error.
// 成功返回输出的字节数, 失败返回-1
#define plogf(type, format, ...) \
(((type) > logs::none && (type) <= logs::glog.level) ? \
	logs::glog.logf((type), __func__, __LINE__, (format), ##__VA_ARGS__) \
	: 0)

